#ifndef ANIMATION_HPP
#define ANIMATION_HPP

#include "config.h"
#define ANIMATION_IMPLEMENTAION

#include "background.hpp"
#include "plane.hpp"

typedef struct Animation {
  // Animation screen dimensions
  int width;
  int height;

  // Animation renderer
  SDL_Renderer *renderer;

  // Background and Plane
  Background background;
  Plane plane;
} Animation;

bool Animation_start(SDL_Renderer *renderer, int width, int height);

bool Animation_load(Animation *animation);
void Animation_destroy(Animation *animation);

bool Animation_handleEvent(Animation *animation, SDL_Event *e);
void Animation_update(Animation *animation, int framerate);
void Animation_render(Animation *animation);

#endif // header file protect

#ifdef ANIMATION_IMPLEMENTAION

inline bool Animation_start(SDL_Renderer *renderer, int width, int height) {
  Animation anim;
  anim.renderer = renderer;
  anim.width = width;
  anim.height = height;

  if (!Animation_load(&anim))
    return false;

  FPSmanager fpsmanager;

  SDL_initFramerate(&fpsmanager);
  SDL_setFramerate(&fpsmanager, FPS_RATE);

  int frame = SDL_getFramecount(&fpsmanager);

  bool quit = false;

  while (!quit) {
    SDL_Event event;
    while (SDL_PollEvent(&event)) {
      quit = Animation_handleEvent(&anim, &event);
    }

    int currentFrame = SDL_getFramecount(&fpsmanager);

    if (currentFrame != frame) {
      Animation_update(&anim, SDL_getFramecount(&fpsmanager));
      currentFrame = frame;
    }

    Animation_render(&anim);

    SDL_RenderPresent(renderer);

    SDL_framerateDelay(&fpsmanager);
  }

  Animation_destroy(&anim);

  return true;
}

inline bool Animation_load(Animation *animation) {
  // Load the ocean image
  if (!Background_load(animation->renderer, &animation->background, OCEAN_IMG))
    return false;

  // Background move direction
  animation->background.direction = DIRECTION_DOWN;

  // Background speed in pixel/second
  animation->background.speed = OCEAN_SPEED;

  if (!Plane_load(animation->renderer, &animation->plane, PLANE_IMG,
                  PLANE_SHADOW)) {
    Background_destroy(&animation->background);
    return false;
  }

  animation->plane.margin = PLANE_MARGIN;
  animation->plane.shadowOffset.x = PLANE_SHADOW_X;
  animation->plane.shadowOffset.y = PLANE_SHADOW_Y;

  // Set plane initial position
  Plane_setX(&animation->plane,
             (animation->width - animation->plane.image.rect.w) /
                 2); // Horiz. center
  Plane_setY(&animation->plane, animation->height -
                                    animation->plane.image.rect.h -
                                    animation->plane.margin);

  // Plane move direction
  animation->plane.direction = DIRECTION_STOP;

  // Plane move speed in pixel/second
  animation->plane.speed = PLANE_SPEED;

  return true;
}

inline void Animation_destroy(Animation *animation) {
  Plane_destroy(&animation->plane);
  Background_destroy(&animation->background);
}

inline bool Animation_handleEvent(Animation *animation, SDL_Event *e) {
  bool quit = false;

  // User requests quit
  if (e->type == SDL_QUIT) {
    quit = true;
  } else if (e->type == SDL_KEYDOWN) {
    switch (e->key.keysym.sym) {
    case SDLK_ESCAPE:
      quit = true;
      break;

    case SDLK_UP:
    case SDLK_DOWN:
    case SDLK_RIGHT:
    case SDLK_LEFT:
      Plane_setDirection(&animation->plane, e->key.keysym.sym);
      break;
    }
  } else if (e->type == SDL_KEYUP) {
    switch (e->key.keysym.sym) {
    case SDLK_UP:
    case SDLK_DOWN:
    case SDLK_RIGHT:
    case SDLK_LEFT:
      Plane_unsetDirection(&animation->plane, e->key.keysym.sym);
      break;
    }
  }

  return quit;
}

inline void Animation_update(Animation *animation, int framerate) {
  // Move ocean
  Background_move(&animation->background, framerate);

  // Move plane
  Plane_move(&animation->plane, animation->width, animation->height, framerate);
}

inline void Animation_render(Animation *animation) {
  // Render ocean
  Background_render(animation->renderer, &animation->background,
                    animation->width, animation->height);

  // Render plane
  Plane_render(animation->renderer, &animation->plane);
}

#endif // impl for above header expose thing